﻿using System;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Web;
// don't do any usings
public partial class HDFileManager : System.Web.UI.Page
{
    protected void Page_Load(object sender, System.EventArgs e)
    {
        if (Request.RequestType == "GET")
        {
            #region GET
            if (Request.QueryString["dl"] == "1")
            {
                string fileName = Server.UrlDecode(Request.QueryString["fn"] ?? string.Empty);
                try
                {
                    if (System.IO.File.Exists(fileName))
                    {
                        System.IO.FileInfo TargetFile = new System.IO.FileInfo(fileName);
                        Response.Clear();
                        Response.AddHeader("Content-Disposition", "attachment; filename=" + TargetFile.Name);
                        Response.AddHeader("Content-Length", TargetFile.Length.ToString());
                        Response.ContentType = "application/octet-stream";
                        Response.TransmitFile(fileName);
                        HttpContext.Current.ApplicationInstance.CompleteRequest();
                    }
                }
                catch (System.Exception ex)
                {
                    Response.Clear();
                    Response.ContentType = "text/html";
                    Response.Write(string.Format("Error providing file: {0}<br/>Message:{1}", fileName, ex.Message));
                    HttpContext.Current.ApplicationInstance.CompleteRequest();
                }
            }
            // using this commands because edit file w/ json will crash if the file is large           
            string command = Request.QueryString["c"];
            switch (command)
            {
                case "getFileContent":
                    string fileName = Request.QueryString["fn"] ?? string.Empty;
                    fileName = Server.UrlDecode(fileName);
                    try
                    {
                        //System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
                        //serializer.MaxJsonLength = System.Int32.MaxValue;

                        //System.Web.HttpContext.Current.Response.Write(serializer.Serialize(GetFileContent(fileName)));
                        System.Web.HttpContext.Current.Response.Write(GetFileContent(fileName));
                        System.Web.HttpContext.Current.Response.ContentType = "text/plain";
                        System.Web.HttpContext.Current.Response.Flush();
                        // using response.end will throw an exception but it won't send the
                        // rest of the file content.
                        //HttpContext.Current.ApplicationInstance.CompleteRequest();
                        System.Web.HttpContext.Current.Response.End();
                    }
                    catch { }
                    break;
            }
            #endregion
        }
        else
        {
            #region POST
            // using this commands because edit file w/ json will crash if the file is large           
            string command = Request.Params["c"];
            switch (command)
            {
                case "saveFileContent":
                    try
                    {
                        string fileName = Request.Params["fn"] ?? string.Empty;
                        fileName = Server.UrlDecode(fileName);
                        string content = Request.Params["cntnt"] ?? string.Empty;
                        bool res = SaveFile(fileName, content);
                        System.Web.HttpContext.Current.Response.Write(res.ToString());
                        System.Web.HttpContext.Current.Response.ContentType = "text/plain";
                        System.Web.HttpContext.Current.Response.Flush();
                        // using response.end will throw an exception but it won't send the
                        // rest of the file content.
                        System.Web.HttpContext.Current.Response.End();
                    }
                    catch
                    {
                        UploadFile();
                    }
                    break;

                case null:
                    UploadFile();
                    break;
            }
            #endregion
        }
    }

    private void UploadFile()
    {
        System.Web.HttpContext.Current.Response.Clear();
        try
        {
            if (fileInput.PostedFile != null)
            {
                string fName = System.IO.Path.GetFileName(fileInput.PostedFile.FileName);
                string destPath = Request.Params["destPath"] ?? string.Empty;
                string filePath = destPath + "\\" + fName;

                DeleteFiles(new string[] { filePath });

                fileInput.PostedFile.SaveAs(filePath);

                System.Web.HttpContext.Current.Response.Write(string.Format("successfully uploaded: {0} bytes at {1}", fileInput.PostedFile.ContentLength.ToString(), filePath));
            }
        }
        catch (Exception ex)
        {
            System.Web.HttpContext.Current.Response.Write(string.Format("ERROR: {0}", ex.Message));
        }

        System.Web.HttpContext.Current.Response.ContentType = "text/plain";
        System.Web.HttpContext.Current.Response.Flush();
        System.Web.HttpContext.Current.Response.End();
    }

    #region Classes & enums
    public enum enumItemType
    {
        file,
        folder
    }

    public class Item
    {
        public string Name { get; set; }
        public string CreatedDate { get; set; }
        public string LastAccessTime { get; set; }
        public long Size { get; set; }
        public string Attributes { get; set; }
        public enumItemType ItemType { get; set; }
    }

    public class RespFolderContent
    {
        public RespFolderContent()
        {
            ItemsList = new System.Collections.Generic.List<Item>();
        }

        public string rootPath { get; set; }
        public System.Collections.Generic.List<Item> ItemsList { get; set; }
        public string Error { get; set; }
    }

    public class RespFileContent
    {
        public string Error { get; set; }
        public string Content { get; set; }
        public string Content2 { get; set; }
    }

    public class DiskDrive
    {
        public DiskDrive()
        {
            DiskLabel = string.Empty;
        }

        public string DriveName { get; set; }
        public string DiskLabel { get; set; }

        public string DriveType { get; set; }
        public long DiskTotalSpace { get; set; }
        public long DiskFreeSpace { get; set; }
    }

    public class RespDiskDrives
    {
        public RespDiskDrives()
        {
            DrivesList = new System.Collections.Generic.List<DiskDrive>();
        }

        public System.Collections.Generic.List<DiskDrive> DrivesList { get; set; }
    }

    public class RespBoolResponse
    {
        public bool Raspuns { get; set; }
        public string Error { get; set; }
    }

    #endregion

    #region Constants
    private const string msgFolderNotFound = "Folder '{0}' not found.";

    #endregion

    #region Web methods

    [System.Web.Services.WebMethod]
    public static RespFolderContent WSGetFolder(string folder, string searchPattern)
    {
        return GetFolderContent(folder, searchPattern);
    }

    [System.Web.Services.WebMethod]
    public static RespDiskDrives WSGetDiskDrives()
    {
        return GetDiskDrives();
    }

    [System.Web.Services.WebMethod]
    public static string WSThisFilesFolder()
    {
        return System.Web.HttpContext.Current.Request.PhysicalApplicationPath.Replace("\\", "/");
    }

    [System.Web.Services.WebMethod]
    public static RespFileContent WSGetFileContent(string filePath)
    {
        var resp = new RespFileContent();
        try
        {
            resp.Content = GetFileContent(filePath);
        }
        catch (System.Exception ex)
        {
            resp.Error = ex.Message;
        }
        return resp;
    }

    [System.Web.Services.WebMethod]
    public static bool WSSaveFileContent(string filePath, string content)
    {
        RemoveReadOnlyAttribute(filePath);
        return SaveFile(filePath, content);
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSDeleteFile(string filePath)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };
        RemoveReadOnlyAttribute(filePath);
        try
        {
            DeleteFiles(new string[] { filePath });
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSCopyFile(string fileOldPath, string fileNewPath)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };
        RemoveReadOnlyAttribute(fileOldPath);
        RemoveReadOnlyAttribute(fileNewPath);
        try
        {
            CopyFile(fileOldPath, fileNewPath);
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSCopyFolder(string folderOldPath, string folderNewPath)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };

        try
        {
            CopyFolder(folderOldPath, folderNewPath);
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSRenameMoveFile(string fileOldPath, string fileNewPath)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };

        try
        {
            RenameMoveFile(fileOldPath, fileNewPath);
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSRenameMoveFolder(string folderOldPath, string folderNewPath)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };

        try
        {
            RenameMoveFolder(folderOldPath, folderNewPath);
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSDeleteFolder(string folderPath)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };

        try
        {
            DeleteFolders(new string[] { folderPath });
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSCreateEmptyItem(string itemPath, string itemType)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };

        try
        {
            if (itemType == "file")
            {
                CreateEmptyFile(itemPath);
            }
            else if (itemType == "folder")
            {
                CreateFolder(itemPath);
            }
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSCreateFolder(string folderPath)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };

        try
        {
            CreateFolder(folderPath);
            raspuns.Raspuns = true;
        }
        catch (System.Exception ex)
        {
            raspuns.Error = ex.Message;
        }
        return raspuns;
    }

    [System.Web.Services.WebMethod]
    public static void WSRecycleAppPool()
    {
        WSRunExe("iisreset.exe", System.Environment.MachineName);
        System.Web.HttpRuntime.UnloadAppDomain();
    }

    [System.Web.Services.WebMethod]
    public static RespBoolResponse WSRunExe(string filePath, string arguments)
    {
        RespBoolResponse raspuns = new RespBoolResponse() { Raspuns = false };
        try
        {
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = filePath;
            proc.StartInfo.Arguments = arguments;
            proc.Start();
            raspuns.Raspuns = true;
        }
        catch (Exception ex) { raspuns.Error = ex.Message; }
        return raspuns;
    }

    #endregion

    #region private methods

    private static RespFolderContent GetFolderContent(string folder, string searchPattern)
    {
        RespFolderContent result = new RespFolderContent();
        result.rootPath = folder;

        try
        {
            if (System.IO.Directory.Exists(folder))
            {
                System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(folder);
                System.IO.DirectoryInfo[] dirs = dir.GetDirectories(searchPattern);

                foreach (var item in dirs)
                {
                    result.ItemsList.Add(new Item() { Name = item.Name, CreatedDate = item.CreationTime.ToString("HH:mm:ss dd.MM.yyyy"), ItemType = enumItemType.folder, LastAccessTime = item.LastAccessTime.ToString("HH:mm:ss dd.MM.yyyy"), Attributes = item.Attributes.ToString() });
                }

                System.IO.FileInfo[] files = dir.GetFiles(searchPattern);
                foreach (var item in files)
                {
                    result.ItemsList.Add(new Item() { Name = item.Name, CreatedDate = item.CreationTime.ToString("HH:mm:ss dd.MM.yyyy"), ItemType = enumItemType.file, LastAccessTime = item.LastAccessTime.ToString("HH:mm:ss dd.MM.yyyy"), Attributes = item.Attributes.ToString(), Size = item.Length });
                }

            }
        }
        catch (System.Exception ex)
        {
            result.Error = ex.Message;
        }

        return result;
    }

    private static string GetFileContent(string filePath)
    {
        if (!System.IO.File.Exists(filePath))
        {
            throw new System.IO.FileNotFoundException("File not found!");
        }

        using (System.IO.StreamReader reader = new System.IO.StreamReader(filePath))
        {
            return reader.ReadToEnd();
        }
    }

    private static bool SaveFile(string filePath, string content)
    {
        if (!string.IsNullOrEmpty(filePath))
        {
            RemoveReadOnlyAttribute(filePath);

            using (System.IO.StreamWriter writer = new System.IO.StreamWriter(filePath, false))
            {
                writer.Write(content);
            }
            return true;
        }
        else
        {
            return false;
        }
    }

    private static RespDiskDrives GetDiskDrives()
    {
        System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives();
        RespDiskDrives response = new RespDiskDrives();

        foreach (var item in drives)
        {
            DiskDrive dd = new DiskDrive() { DriveName = item.Name.Substring(0, 1), DriveType = item.DriveType.ToString() };

            if (item.IsReady)
            {
                dd.DiskTotalSpace = item.TotalSize;
                dd.DiskFreeSpace = item.TotalFreeSpace;
                dd.DiskLabel = item.VolumeLabel ?? string.Empty;
            }
            response.DrivesList.Add(dd);
        }

        return response;
    }

    private static void CopyItems(string[] files, string destination, bool overridde = true)
    {
        if (files != null && files.Length > 0)
        {
            string[] serverList = files.Select(f => MapFile(f)).ToArray();
            string serverDestination = MapFolder(destination);

            foreach (var file in serverList)
            {
                System.IO.FileInfo fileInfo = new System.IO.FileInfo(file);
                string newPath = System.IO.Path.Combine(serverDestination, fileInfo.Name);

                if (System.IO.File.Exists(newPath))
                {
                    if (overridde)
                    {
                        System.IO.File.Delete(newPath);
                        System.IO.File.Copy(file, newPath);
                    }
                    else
                    {
                        throw new System.Exception("File already exist !");
                    }
                }
            }
        }
    }

    private static void MoveFiles(string[] files, string destination, bool overridde = true)
    {
        if (files != null && files.Count() > 0)
        {
            string[] serverList = files.Select(f => MapFile(f)).ToArray();
            string serverDestination = MapFolder(destination);

            foreach (var file in serverList)
            {
                System.IO.FileInfo fileInfo = new System.IO.FileInfo(file);
                string newPath = System.IO.Path.Combine(serverDestination, fileInfo.Name);

                if (System.IO.File.Exists(newPath))
                {
                    if (overridde)
                    {
                        System.IO.File.Delete(newPath);
                        System.IO.File.Move(file, newPath);
                    }
                    else
                    {
                        throw new System.Exception("File already exist !");
                    }
                }
            }
        }
    }

    private static void DeleteFiles(string[] files)
    {
        if (files != null && files.Count() > 0)
        {
            foreach (var item in files)
            {
                if (File.Exists(item))
                {
                    RemoveReadOnlyAttribute(item);

                    System.IO.File.Delete(item);
                }
            }
        }
    }

    private static void DeleteFolders(string[] folders)
    {
        if (folders != null && folders.Count() > 0)
        {
            //string[] serverList = files.Select(f => MapFile(f)).ToArray();
            foreach (var item in folders)
            {
                System.IO.Directory.Delete(item, true);
            }
        }
    }

    private static void CopyFile(string fileOldPath, string fileNewPath, bool overwrite = true)
    {
        if (string.IsNullOrEmpty(fileOldPath) || string.IsNullOrEmpty(fileNewPath))
        {
            throw new Exception("Both variables need to contain data!");
        }

        FileInfo fi = new FileInfo(fileOldPath);
        fileNewPath += Path.AltDirectorySeparatorChar + Path.GetFileName(fileOldPath);
        fi.CopyTo(fileNewPath, overwrite);

    }

    private static void CopyFolder(string folderOldPath, string folderNewPath, bool overwite = true)
    {
        if (string.IsNullOrEmpty(folderOldPath) || string.IsNullOrEmpty(folderNewPath))
        {
            throw new Exception("Both variables need to contain data!");
        }

        DirectoryInfo sourceDi = new DirectoryInfo(folderOldPath);

        string path = folderNewPath + Path.DirectorySeparatorChar + sourceDi.Name;
        DirectoryInfo di = new DirectoryInfo(path);

        if (!di.Exists)
            di.Create();

        foreach (DirectoryInfo childrenDi in sourceDi.EnumerateDirectories())
            CopyFolder(childrenDi.FullName, di.FullName, overwite);

        foreach (FileInfo childFi in sourceDi.GetFiles())
            CopyFile(childFi.FullName, di.FullName);

        //        System.IO.Directory.Copy(folderOldPath, folderNewPath);
    }

    private static void RenameMoveFile(string fileOldPath, string fileNewPath)
    {
        if (string.IsNullOrEmpty(fileOldPath) || string.IsNullOrEmpty(fileNewPath))
        {
            throw new Exception("Both variables need to contain data!");
        }
        RemoveReadOnlyAttribute(fileNewPath);
        RemoveReadOnlyAttribute(fileOldPath);
        System.IO.File.Move(fileOldPath, fileNewPath);
    }

    private static void RenameMoveFolder(string folderOldPath, string folderNewPath)
    {
        if (string.IsNullOrEmpty(folderOldPath) || string.IsNullOrEmpty(folderNewPath))
        {
            throw new Exception("Both variables need to contain data!");
        }
        System.IO.Directory.Move(folderOldPath, folderNewPath);
    }

    private static void CreateEmptyFile(string filePath)
    {
        if (string.IsNullOrEmpty(filePath))
        {
            throw new Exception("File path is empty!");
        }
        StreamWriter sw = System.IO.File.CreateText(filePath);
        sw.Close();
    }

    private static void CreateFolder(string folderPath)
    {
        if (string.IsNullOrEmpty(folderPath))
        {
            throw new Exception("Folder path is empty!");
        }
        Directory.CreateDirectory(folderPath);
    }

    private static void RemoveReadOnlyAttribute(string filePath)
    {
        try
        {
            if (System.IO.File.Exists(filePath))
                File.SetAttributes(filePath, File.GetAttributes(filePath) & ~FileAttributes.ReadOnly);
        }
        catch { }
    }

    private static void CopyStream(Stream source, Stream target)
    {
        const int bufSize = 0x1000;
        byte[] buf = new byte[bufSize];
        int bytesRead = 0;
        while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)
            target.Write(buf, 0, bytesRead);
    }

    #endregion

    #region helping methods

    private static string EscapeJSON(string json)
    {
        return json.Replace("'", "\'");
    }

    private static string MapFile(string filePath)
    {
        if (System.Web.HttpContext.Current != null && !string.IsNullOrEmpty(filePath))
        {
            var path = System.Web.HttpContext.Current.Server.MapPath(filePath);

            if (!System.IO.File.Exists(path))
            {
                throw new System.IO.FileNotFoundException();
            }

            return path;
        }
        else
        {
            throw new System.NullReferenceException("HttpContext.Current or filePath");
        }
    }

    private static string MapFolder(string folderPath)
    {
        if (System.Web.HttpContext.Current != null && !string.IsNullOrEmpty(folderPath))
        {
            var path = System.Web.HttpContext.Current.Server.MapPath(folderPath);

            if (!System.IO.Directory.Exists(path))
            {
                throw new System.IO.FileNotFoundException();
            }

            return path;
        }
        else
        {
            throw new System.NullReferenceException("HttpContext.Current or folderPath");
        }
    }
    #endregion
}